﻿using System;
using System.Linq;
using System.ComponentModel;
using System.Windows.Input;
using Com.CodePlex.SPPower.Controller;
using Com.CodePlex.SPPower.Data;
using System.Collections.ObjectModel;
using System.Collections.Generic;

namespace Com.CodePlex.SPPower.ViewModel {

	public class MainWindowViewModel : ViewModel {

		public static readonly string APPLICATION_NAME = "Com.CodePlex.SPPower";

		public MainWindowViewModel() {
			DisplayName = MainWindowViewModel.APPLICATION_NAME;
			Mediator.Register(this);
			//note: lazy load: dont do more stuff here
			TreeRootItems.Add(new CmdViewModel(new Model.Cmd() { Name = "Loading ..." }, null));
		}

		#region Commands

		private ICommand exitcommand;
		public ICommand ExitCommand { get { return exitcommand ?? (exitcommand = new RelayCommand(param => OnRequestExit())); } }

		private ICommand runcommand;
		public ICommand RunCommand { get { return runcommand ?? (runcommand = new RelayCommand(param => Run(), param => CanRun())); } }

		#endregion

		#region Display Properties

		private string statusbartext;
		public string StatusBarText {
			get { return statusbartext; }
			private set {
				if (statusbartext != value) {
					statusbartext = value;
					OnPropertyChanged(() => StatusBarText);
				}
			}
		}

		private bool isprogressbarvisible;
		public bool IsProgressBarVisible {
			get { return isprogressbarvisible; }
			private set {
				if (isprogressbarvisible != value) {
					isprogressbarvisible = value;
					OnPropertyChanged(() => IsProgressBarVisible);
				}
			}
		}

		private System.Windows.Visibility parametersvisiblity = System.Windows.Visibility.Hidden;
		public System.Windows.Visibility ParametersVisiblity {
			get { return parametersvisiblity; }
			private set {
				if (parametersvisiblity != value) {
					parametersvisiblity = value;
					OnPropertyChanged(() => ParametersVisiblity);
				}
			}
		}

		private int progress;
		public int Progress {
			get { return progress; }
			private set {
				if (progress != value) {
					progress = value;
					OnPropertyChanged(() => Progress);
				}
			}
		}

		private ObservableCollection<CmdParameterViewModel> parameters;
		public ObservableCollection<CmdParameterViewModel> Parameters {
			get {
				if (parameters == null) {
					parameters = new ObservableCollection<CmdParameterViewModel>();
				}
				return parameters;
			}
		}

		private ObservableCollection<HistoryViewModel> history;
		public ObservableCollection<HistoryViewModel> History {
			get {
				if (history == null) {
					history = new ObservableCollection<HistoryViewModel>();
				}
				return history;
			}
		}

		private ObservableCollection<ViewModel> treerootitems;
		public ObservableCollection<ViewModel> TreeRootItems {
			get {
				if (treerootitems == null) {
					treerootitems = new ObservableCollection<ViewModel>();
				}
				return treerootitems;
			}
		}

		#endregion

		class LoadResult {
			public IList<object> RootItems;
			public IList<string> NoCategoryCmds;
			public IList<HistoryViewModel> History;
		}

		public void Load() {
            StatusBarText = "Loading...";
			BackgroundWorker bgworker = new BackgroundWorker();
			bgworker.DoWork += (s, e) => {
				e.Result = new LoadResult() { 
					RootItems = new CmdRepository().FindRootItems(), 
					NoCategoryCmds = new Service.AutomationService().GetNoCategoryCmds(),
					History = new HistoryRepository().Load()
				};
			};
			bgworker.RunWorkerCompleted += (s, e) => {
				if (e.Error != null) {

				} else {
					StatusBarText = "Ready";
					IsProgressBarVisible = false;
				}
				LoadResult result = (LoadResult)e.Result;
				TreeRootItems.Clear();
				(
					from item in result.RootItems
					where item is Model.CmdCategory
					select (ViewModel)(new CmdCategoryViewModel((Model.CmdCategory)item, null))
				).Union(
					from item in result.RootItems
					where item is Model.Cmd
					select (ViewModel)(new CmdViewModel((Model.Cmd)item, null))
				).ToList<ViewModel>().ForEach(
					i => {
						TreeRootItems.Add(i);
					}
				);
				result.History.ToList().ForEach(i => {
					History.Add(i);
				});
				CmdCategoryViewModel model = new CmdCategoryViewModel(null, null);
				model.RemoveDummy();
				result.NoCategoryCmds.ToList().ForEach(i => {
                    model.Children.Add(new CmdViewModel(new Model.Cmd() { Name = i }, model));
				});
				TreeRootItems.Add(model);
				CommandManager.InvalidateRequerySuggested();
			};
			IsProgressBarVisible = true;
			bgworker.RunWorkerAsync();
		}

		private CmdViewModel CurrentCmd; //todo: make better MVVM with IsSelected property and tree search

		public void SelectCmd(object item) {
            if (CurrentCmd == item) {
                return;
            }
			ParametersVisiblity = System.Windows.Visibility.Hidden;
			parameters.Clear();
			CurrentCmd = null;
			if (item is CmdViewModel) {
				CurrentCmd = (CmdViewModel)item;
				IList<Service.CmdParameter> paras = new Service.AutomationService().GetParameters(((CmdViewModel)item).Item);
				if (paras != null) {
					ParametersVisiblity = System.Windows.Visibility.Visible;
					paras.ToList().ForEach(i => {
						parameters.Add(new CmdParameterViewModel(i.Name, i.Type));
					});
				}
			}
		}

		private bool CanRun() {
			return true;
		}

        class RunResult {
            public IList<string> LogRows;
            public IList<Service.CmdParameter> Parameters;
        }

		private void Run() {
            StatusBarText = "Running...";
			HistoryViewModel history = new HistoryViewModel(CurrentCmd.Item.Name, DateTime.Now);
			BackgroundWorker bgworker = new BackgroundWorker();
			bgworker.WorkerReportsProgress = true;
			bgworker.DoWork += (s, e) => {
                RunResult result = new RunResult();
                result.Parameters = Parameters.Select(i => new Service.CmdParameter() { Name = i.DisplayName, Value = i.Value, Type = i.Type }).ToList();
                result.LogRows = new Service.AutomationService().RunPowerShellScript(CurrentCmd.Item.Name, result.Parameters);
                e.Result = result;
			};
			bgworker.ProgressChanged += (s, e) => {
				
			};
			bgworker.RunWorkerCompleted += (s, e) => {
				if (e.Error != null) {

				} else {
					
				}
                StatusBarText = "Ready";
                IsProgressBarVisible = false;
                RunResult result = (RunResult)e.Result;
                string log = "";
				result.LogRows.ToList().ForEach(i => {
					log += i + "\n";
				});
                history.Parameters = result.Parameters;
                history.Log += log;
				new HistoryRepository().Append(history);
			};
			IsProgressBarVisible = true;
			History.ToList().ForEach(i => {
				i.IsExpanded = false;
			});
			history.IsExpanded = true;
			history.IsAutoScroll = true;
			History.Add(history);
			bgworker.RunWorkerAsync();
		}

        [MediatorMessageSink(SimpleMessage.LoadHistoryItem, ParameterType = typeof(SimpleMessage))]
        public void LoadHistoryItem(SimpleMessage message) {
            try {
                HistoryViewModel historymodel = (HistoryViewModel)message.Object;
                CmdViewModel cmdmodel = FindViewModel(TreeRootItems, historymodel.Cmd) as CmdViewModel;
                if (cmdmodel != null) {
                    cmdmodel.IsExpanded = true;
                    cmdmodel.IsSelected = true; //careful, double selects happening here
                    SelectCmd(cmdmodel); //force select so know parameters are created

                    parameters.ToList().ForEach(i => {
                        Service.CmdParameter para = historymodel.Parameters.SingleOrDefault(j => j.Name == i.DisplayName);
                        if (para != null && para.Value != null) {
                            i.Value = para.Value;
                        }
                    });
                }
            } catch (Exception ex) {
                throw ex;
            }
        }

        private ViewModel FindViewModel(ObservableCollection<ViewModel> items, string name) {
            foreach (ViewModel i in items) {
                if (i is CmdCategoryViewModel) {
                    ViewModel result = FindViewModel(((CmdCategoryViewModel)i).Children, name);
                    if (result != null) {
                        return result;
                    }
                } else if (i is CmdViewModel) {
                    if (((CmdViewModel)i).DisplayName == name) {
                        return i;
                    }
                }
            }
            return null;
        }

		#region Exit

		public event EventHandler RequestExit;

		private void OnRequestExit() {
			if (RequestExit != null) {
				RequestExit(this, EventArgs.Empty);
			}
		}

		public bool WarnExit() {
			return true;
		}

		public void Exit() {
			
		}

		#endregion
	}
}